package com.gitee.wsl.transform.format.base

import com.gitee.wsl.ext.base.DASHED
import com.gitee.wsl.ext.base.UNDERLINE
import com.gitee.wsl.ext.string.upperFirst
import com.gitee.wsl.transform.format.Format
import com.gitee.wsl.transform.format.StringFormat

class TextCase(val words: List<String>) {
    companion object {
        operator fun invoke(str: String): TextCase {
            // @TODO:
            //   - hello_World
            //   - SNAKE_CASE
            //   - TEST-DEMO
            //   - helloWorld
            //   - HelloWorld
            return TextCase(str.replace('_', '-').split(Regex("\\W+")))
            //val out = arrayListOf<String>()
            //val sr = StrReader(str)
            //var lastLowerCase: Boolean? = null
            //while (sr.hasMore) {
            //    val lowerCase = sr.peek().isLowerCase()
            //    val changedCase = (lowerCase != lastLowerCase)
            //    if (changedCase) {
            //    }
            //    lastLowerCase = lowerCase
            //}
            //return TextCase(out)
        }

        /**
         * 将驼峰式命名的字符串转换为下划线方式，又称SnakeCase、underScoreCase。<br></br>
         * 如果转换前的驼峰式命名的字符串为空，则返回空字符串。<br></br>
         * 规则为：
         *
         *  * 单字之间以下划线隔开
         *  * 每个单字的首字母亦用小写字母
         *
         * 例如：
         *
         * <pre>
         * HelloWorld=》hello_world
         * Hello_World=》hello_world
         * HelloWorld_test=》hello_world_test
        </pre> *
         *
         * @param str 转换前的驼峰式命名的字符串，也可以为下划线形式
         * @return 转换后下划线方式命名的字符串
         */
        fun toUnderlineCase(str: CharSequence): String {
            return toSymbolCase(str, Char.UNDERLINE)
        }

        /**
         * 将驼峰式命名的字符串转换为短横连接方式。<br></br>
         * 如果转换前的驼峰式命名的字符串为空，则返回空字符串。<br></br>
         * 规则为：
         *
         *  * 单字之间横线线隔开
         *  * 每个单字的首字母亦用小写字母
         *
         * 例如：
         *
         * <pre>
         * HelloWorld=》hello-world
         * Hello_World=》hello-world
         * HelloWorld_test=》hello-world-test
        </pre> *
         *
         * @param str 转换前的驼峰式命名的字符串，也可以为下划线形式
         * @return 转换后下划线方式命名的字符串
         */
        fun toKebabCase(str: CharSequence): String {
            return toSymbolCase(str, Char.DASHED)
        }

        /**
         * 将驼峰式命名的字符串转换为使用符号连接方式。如果转换前的驼峰式命名的字符串为空，则返回空字符串。
         *
         * @param str    转换前的驼峰式命名的字符串，也可以为符号连接形式
         * @param symbol 连接符
         * @return 转换后符号连接方式命名的字符串
         * @since 4.0.10
         */
        fun toSymbolCase(str: CharSequence, symbol: Char): String {
            val length = str.length
            val sb = StringBuilder()
            var c: Char
            for (i in 0..<length) {
                c = str.get(i)
                if (c.isUpperCase()) {
                    val preChar = if (i > 0) str.get(i - 1) else null
                    val nextChar = if (i < str.length - 1) str.get(i + 1) else null

                    if (null != preChar) {
                        if (symbol == preChar) {
                            // 前一个为分隔符
                            if (null == nextChar || nextChar.isLowerCase()) {
                                //普通首字母大写，如_Abb -> _abb
                                c = c.lowercaseChar()
                            }
                            //后一个为大写，按照专有名词对待，如_AB -> _AB
                        } else if (preChar.isLowerCase()) {
                            // 前一个为小写
                            sb.append(symbol)
                            if (null == nextChar || nextChar.isLowerCase() || nextChar.isDigit()) {
                                //普通首字母大写，如aBcc -> a_bcc
                                c = c.lowercaseChar()
                            }
                            // 后一个为大写，按照专有名词对待，如aBC -> a_BC
                        } else {
                            //前一个为大写
                            if (null != nextChar && nextChar.isLowerCase()) {
                                // 普通首字母大写，如ABcc -> A_bcc
                                sb.append(symbol)
                                c = c.lowercaseChar()
                            }
                            // 后一个为大写，按照专有名词对待，如ABC -> ABC
                        }
                    } else {
                        // 首字母，需要根据后一个判断是否转为小写
                        if (null == nextChar || nextChar.isLowerCase()) {
                            // 普通首字母大写，如Abc -> abc
                            c = c.lowercaseChar()
                        }
                        // 后一个为大写，按照专有名词对待，如ABC -> ABC
                    }
                }
                sb.append(c)
            }
            return sb.toString()
        }

        /**
         * 将下划线方式命名的字符串转换为帕斯卡式。<br></br>
         * 规则为：
         *
         *  * 单字之间不以空格或任何连接符断开
         *  * 第一个单字首字母采用大写字母
         *  * 后续单字的首字母亦用大写字母
         *
         * 如果转换前的下划线大写方式命名的字符串为空，则返回空字符串。<br></br>
         * 例如：hello_world=》HelloWorld
         *
         * @param name 转换前的下划线大写方式命名的字符串
         * @return 转换后的驼峰式命名的字符串
         */
        fun toPascalCase(name: CharSequence): String {
            return toCamelCase(name).upperFirst()
        }

        /**
         * 将下划线方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空，则返回空字符串。<br></br>
         * 规则为：
         *
         *  * 单字之间不以空格或任何连接符断开
         *  * 第一个单字首字母采用小写字母
         *  * 后续单字的首字母亦用大写字母
         *
         * 例如：hello_world=》helloWorld
         *
         * @param name 转换前的下划线大写方式命名的字符串
         * @return 转换后的驼峰式命名的字符串
         */
        fun toCamelCase(name: CharSequence): String {
            return toCamelCase(name, Char.UNDERLINE)
        }

        /**
         * 将连接符方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空，则返回空字符串。
         *
         * @param name   转换前的自定义方式命名的字符串
         * @param symbol 原字符串中的连接符连接符
         * @return 转换后的驼峰式命名的字符串
         * @since 5.7.17
         */
        fun toCamelCase(name: CharSequence, symbol: Char): String {
            return toCamelCase(name, symbol, true)
        }

        /**
         * 将连接符方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空，则返回空字符串。
         *
         * @param name             转换前的自定义方式命名的字符串
         * @param symbol           原字符串中的连接符连接符
         * @param otherCharToLower 其他非连接符后的字符是否需要转为小写
         * @return 转换后的驼峰式命名的字符串
         */
        fun toCamelCase(name: CharSequence, symbol: Char, otherCharToLower: Boolean): String {

            val name2 = name.toString()
            if (name2.contains(symbol)) {
                val length = name2.length
                val sb = StringBuilder(length)
                var upperCase = false
                for (i in 0..<length) {
                    val c = name2.get(i)

                    if (c == symbol) {
                        upperCase = true
                    } else if (upperCase) {
                        sb.append(c.uppercaseChar())
                        upperCase = false
                    } else {
                        sb.append(if (otherCharToLower) c.lowercaseChar() else c)
                    }
                }
                return sb.toString()
            } else {
                return name2
            }
        }

    }

    fun spaceCase(): String = words.joinToString(" ") { it.lowercase() }
    fun snakeCase(): String = words.joinToString("_") { it.lowercase() }
    fun kebabCase(): String = words.joinToString("_") { it.lowercase() }
    fun screamingSnakeCase(): String = words.joinToString("_") { it.uppercase() }
    fun pascalCase(): String = words.joinToString("") { it.lowercase().replaceFirstChar { it.uppercaseChar() } }
    fun camelCase(): String {
        var first = true
        return words.joinToString("") {
            if (first) {
                first = false
                it.lowercase()
            } else {
                it.lowercase().replaceFirstChar { it.uppercaseChar() }
            }
        }
    }
}

internal fun String.toTextCase(): TextCase = TextCase(this)

val Format.Companion.camelCase: StringFormat
    get() = StringFormat{ src -> src.toTextCase().camelCase()}

val Format.Companion.pascalCase: StringFormat
    get() = StringFormat{ src -> src.toTextCase().pascalCase()}

val Format.Companion.screamingSnakeCase: StringFormat
    get() = StringFormat{ src -> src.toTextCase().screamingSnakeCase()}

val Format.Companion.kebabCase: StringFormat
    get() = StringFormat{ src -> src.toTextCase().kebabCase()}

val Format.Companion.snakeCase: StringFormat
    get() = StringFormat{ src -> src.toTextCase().snakeCase()}

val Format.Companion.spaceCase: StringFormat
    get() = StringFormat{ src -> src.toTextCase().spaceCase()}